package cn.edu.sgu.www.mhxysy.function.forger.equipment;

import cn.edu.sgu.www.mhxysy.consts.IdentifierPrefixes;
import cn.edu.sgu.www.mhxysy.dto.equipment.EquipmentForgeDTO;
import cn.edu.sgu.www.mhxysy.entity.equipment.*;
import cn.edu.sgu.www.mhxysy.entity.except.Property;
import cn.edu.sgu.www.mhxysy.entity.role.RoleAccount;
import cn.edu.sgu.www.mhxysy.enums.*;
import cn.edu.sgu.www.mhxysy.exception.GlobalException;
import cn.edu.sgu.www.mhxysy.factory.impl.EquipmentFactory;
import cn.edu.sgu.www.mhxysy.function.computer.score.impl.EquipmentScoreComputer;
import cn.edu.sgu.www.mhxysy.function.forger.Forger;
import cn.edu.sgu.www.mhxysy.mapper.equipment.*;
import cn.edu.sgu.www.mhxysy.mapper.except.PropertyMapper;
import cn.edu.sgu.www.mhxysy.mapper.role.RoleAccountMapper;
import cn.edu.sgu.www.mhxysy.redis.RedisUtils;
import cn.edu.sgu.www.mhxysy.restful.ResponseCode;
import cn.edu.sgu.www.mhxysy.util.CollectionUtils;
import cn.edu.sgu.www.mhxysy.util.MathUtils;
import cn.edu.sgu.www.mhxysy.util.UserUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 装备打造器
 * @author 沐雨橙风ιε
 * @version 1.0
 */
@Component
public class EquipmentForger implements Forger {

    private final RedisUtils redisUtils;
    private final PropertyMapper propertyMapper;
    private final EquipmentMapper equipmentMapper;
    private final RoleAccountMapper roleAccountMapper;
    private final EquipmentTejiMapper equipmentTejiMapper;
    private final EquipmentTypeMapper equipmentTypeMapper;
    private final EquipmentTexiaoMapper equipmentTexiaoMapper;
    private final EquipmentScoreComputer equipmentScoreComputer;
    private final EquipmentCategoryMapper equipmentCategoryMapper;
    private final EquipmentAttributeMapper equipmentAttributeMapper;
    private final EquipmentViewAttributeMapper equipmentViewAttributeMapper;
    private final EquipmentAttributeRangeMapper equipmentAttributeRangeMapper;

    @Autowired
    public EquipmentForger(
            RedisUtils redisUtils,
            PropertyMapper propertyMapper,
            EquipmentMapper equipmentMapper,
            RoleAccountMapper roleAccountMapper,
            EquipmentTejiMapper equipmentTejiMapper,
            EquipmentTypeMapper equipmentTypeMapper,
            EquipmentTexiaoMapper equipmentTexiaoMapper,
            EquipmentScoreComputer equipmentScoreComputer,
            EquipmentCategoryMapper equipmentCategoryMapper,
            EquipmentAttributeMapper equipmentAttributeMapper,
            EquipmentViewAttributeMapper equipmentViewAttributeMapper,
            EquipmentAttributeRangeMapper equipmentAttributeRangeMapper) {
        this.redisUtils = redisUtils;
        this.propertyMapper = propertyMapper;
        this.equipmentMapper = equipmentMapper;
        this.roleAccountMapper = roleAccountMapper;
        this.equipmentTejiMapper = equipmentTejiMapper;
        this.equipmentTypeMapper = equipmentTypeMapper;
        this.equipmentTexiaoMapper = equipmentTexiaoMapper;
        this.equipmentScoreComputer = equipmentScoreComputer;
        this.equipmentCategoryMapper = equipmentCategoryMapper;
        this.equipmentAttributeMapper = equipmentAttributeMapper;
        this.equipmentViewAttributeMapper = equipmentViewAttributeMapper;
        this.equipmentAttributeRangeMapper = equipmentAttributeRangeMapper;
    }

    @Override
    public Void apply(Object param) {
        if (param instanceof EquipmentForgeDTO) {
            // 解析参数
            EquipmentForgeDTO equipmentForgeDTO = (EquipmentForgeDTO) param;

            // 得到装备类型ID
            Integer categoryId = equipmentForgeDTO.getEquipmentId();
            // 查询装备类型信息
            EquipmentCategory equipmentCategory = equipmentCategoryMapper.selectById(categoryId);

            if (equipmentCategory == null) {
                throw new GlobalException(ResponseCode.CONFLICT, "操作失败，装备类型不存在！");
            }

            /*
             * 装备打造
             * 1、验证角色等级是否大于装备等级10级
             * 2、为装备生成属性（普通属性+附加属性）
             * 3、为装备生成特技、特效
             * 4、保存装备信息
             * 5、修改装备评分：根据装备的等级、属性、特技、特效计算得到
             */
            String userId = UserUtils.getUserId();

            // 得到角色信息
            RoleAccount roleAccount = roleAccountMapper.selectById(userId);

            Integer grade = equipmentCategory.getGrade();

            // 1、验证角色等级是否大于装备等级10级
            if (grade - roleAccount.getGrade() > 10) { // 大于10级，抛出异常
                throw new GlobalException(ResponseCode.FORBIDDEN, "只能打造不超过角色等级10级的装备。");
            }

            // 生成装备ID
            String equipmentId = IdentifierPrefixes.PREFIX_JSZB + redisUtils.uuid();

            /*
             * 2、保存装备信息
             */
            EquipmentFactory equipmentFactory = new EquipmentFactory();
            Equipment equipment = equipmentFactory.produce();

            equipment.setForgeType(equipmentForgeDTO.getForgeType());
            equipment.setFulingStatus(FulingStatus.WFL.getValue());
            equipment.setWearStatus(WearStatus.WCD.getValue());
            equipment.setForger(roleAccount.getName());
            equipment.setCategoryId(categoryId);
            equipment.setId(equipmentId);
            equipment.setRoleId(userId);

            /*
             * 设置装备特技、特效
             */
            // 1/10概率附带特效
            if (MathUtils.random(1, 10) == 5) {
                List<EquipmentTexiao> texiaos = equipmentTexiaoMapper.selectList(null);
                int size = texiaos.size();

                // 生成随机特效ID
                int random = MathUtils.random(1, size - 1);

                equipment.setTexiaoId(texiaos.get(random).getId());
            }

            // 1/10概率附带特技
            if (MathUtils.random(1, 10) == 5) {
                List<EquipmentTeji> list = equipmentTejiMapper.selectList(null);

                // 生成随机特技ID
                int index = MathUtils.random(1, list.size() - 1);

                equipment.setTejiId(list.get(index).getId());
            }

            equipmentMapper.insert(equipment); // 添加装备

            Integer topType = equipmentTypeMapper.selectTopType(categoryId);

            /*
             * 添加装备属性
             */
            // 差询装备预览属性
            QueryWrapper<EquipmentViewAttribute> queryWrapper1 = new QueryWrapper<>();

            queryWrapper1.eq("grade", grade);
            queryWrapper1.eq("equipment_id", topType);
            queryWrapper1.eq("forge_type", equipmentForgeDTO.getForgeType());

            List<EquipmentViewAttribute> viewAttributes = equipmentViewAttributeMapper.selectList(queryWrapper1);

            // 为装备添加[min, max]随机的默认属性值
            if (CollectionUtils.isNotEmpty(viewAttributes)) {
                for (EquipmentViewAttribute viewAttribute : viewAttributes) {
                    EquipmentAttribute attribute = new EquipmentAttribute();
                    // 得到装备预览属性的属性id
                    Integer propertyId = viewAttribute.getPropertyId();
                    // 生成[min, max]的随机值
                    int random = MathUtils.random(viewAttribute.getMin(), viewAttribute.getMax());

                    // 设置装备属性信息
                    attribute.setId(IdentifierPrefixes.PREFIX_ZBSX + redisUtils.uuid());
                    attribute.setType(EquipmentAttributeTypes.PUTONG.getValue()); // 普通属性
                    attribute.setEquipmentId(equipmentId);
                    attribute.setPropertyId(propertyId);
                    attribute.setPropertyValue(random);

                    // 为装备添加属性
                    equipmentAttributeMapper.insert(attribute);
                }
            }

            // 武器和衣服考虑附加属性
            if (EquipmentTypes.WUQI.getValue().equals(topType) || EquipmentTypes.YIJIA.getValue().equals(topType)) {
                // 定义附加属性的词条数
                int[] array = {0, 1, 2};

                // 得到随机的附加属性条数
                int count = array[MathUtils.random(0, array.length - 1)];

                if (count > 0) {
                    // 根据装备等级查询装备双加属性上限
                    QueryWrapper<EquipmentAttributeRange> queryWrapper = new QueryWrapper<>();

                    queryWrapper.eq("grade", grade);

                    EquipmentAttributeRange range = equipmentAttributeRangeMapper.selectOne(queryWrapper);

                    Integer maxValue; // 最大属性值

                    if (count == 1) {
                        maxValue = range.getSinglePlus();
                    } else {
                        maxValue = range.getDoublePlus();
                    }

                    // 查询附加属性列表
                    Map<String, Object> columnMap = new HashMap<>(1);

                    columnMap.put("type", PropertyTypes.FJSX.getValue());

                    List<Property> list = propertyMapper.selectByMap(columnMap);

                    // 为装备添加对应条数的附加属性
                    for (int i = 0; i < count; i++) {
                        // 获得随机属性
                        Property property = list.get(MathUtils.random(0, list.size() - 1));

                        EquipmentAttribute equipmentAttribute = new EquipmentAttribute();

                        equipmentAttribute.setId(IdentifierPrefixes.PREFIX_ZBSX + redisUtils.uuid());
                        equipmentAttribute.setType(EquipmentAttributeTypes.PUTONG.getValue());
                        equipmentAttribute.setPropertyId(property.getId());
                        equipmentAttribute.setEquipmentId(equipmentId);
                        equipmentAttribute.setPropertyValue(MathUtils.random(1, maxValue));

                        equipmentAttributeMapper.insert(equipmentAttribute);

                        // 移除该属性，防止多次添加同种属性
                        if (count > 1) {
                            list.remove(property);
                        }
                    }
                }
            }

            // 3、修改装备评分
            UpdateWrapper<Equipment> updateWrapper = new UpdateWrapper<>();

            updateWrapper.eq("id", equipmentId);
            updateWrapper.set("score", equipmentScoreComputer.compute(equipmentId));

            equipmentMapper.update(updateWrapper.getEntity(), updateWrapper);
        }

        return null;
    }

}